package pl.lodz.p.browarex.ws;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;

import javax.annotation.PostConstruct;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.XmlMappingException;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import pl.lodz.p.browarex.ws.model.AnalysisRequest;
import pl.lodz.p.browarex.ws.model.OrderResponse;
import pl.lodz.p.browarex.ws.model.Pop;
import pl.lodz.p.browarex.ws.model.PopResponse;
import pl.lodz.p.browarex.ws.model.ProductDistRequest;
import pl.lodz.p.browarex.ws.model.Push;
import pl.lodz.p.browarex.ws.model.Statement;

@Component
public class BeerEndpoint extends AbstractSSLEndpoint {

	private static final Log log = LogFactory.getLog(BeerEndpoint.class);

	@Value("${guid.crm}")
	private String guidCrm;

	@Value("${guid.ss}")
	private String guidSs;

	@Value("${guid.sd}")
	private String guidSd;

	@Value("${guid.auth}")
	private String guidAuth;

	@Value("${keystore.url}")
	private String keystoreUrl;

	@Value("${keystore.pass}")
	private String keystorePass;

	@Value("${truststore.url}")
	private String truststoreUrl;

	@Value("${truststore.pass}")
	private String truststorePass;

	@Autowired
	private Marshaller marshaller;

	@Autowired
	private Unmarshaller unmarshaller;

	@Autowired
	private Processor processor;

	@Autowired
	private ClasspathResourceLoader resourceLoader;

	@PostConstruct
	public void initWebService() {
		setUpSSLWebServiceTemplate();
	}

	@Scheduled(fixedDelay = 10 * 1000)
	public void popData() {
		Pop popRequest = new Pop();
		popRequest.setSystemGuid(guidSs);
		log.debug(guidSs);
		PopResponse popResponse = (PopResponse) getWebServiceTemplate()
				.marshalSendAndReceive(popRequest);
		for (Statement statement : popResponse.getReturns()) {
			log.info("Data received from JMS: " + statement.getContent());
			processContent(statement.getContent());
		}
	}

	public void pushData(String content) {
		Push pushRequest = new Push();
		Statement statement = new Statement();
		statement.setSender(guidSs);
		statement.setReceiver(guidSd);
		statement.setContent(content);
		log.info("Data send to JMS: " + content);
		pushRequest.setStatement(statement);
		getWebServiceTemplate().marshalSendAndReceive(pushRequest);
		statement.setReceiver(guidCrm);
		pushRequest.setStatement(statement);
		getWebServiceTemplate().marshalSendAndReceive(pushRequest);
	}

	private void processContent(String content) {
		Object pojo = unmarshal(content);
		if (pojo instanceof ProductDistRequest) {
			log.info("Processing product message started...");
			ProductDistRequest productReq = (ProductDistRequest) pojo;
			processor.processProductDistRequest(productReq);
			log.info("Processing product message fininshed!");
		} else if (pojo instanceof OrderResponse) {
			log.info("Processing orderResponse message started...");
			OrderResponse response = (OrderResponse) pojo;
			processor.processOrderResponse(response);
			log.info("Processing orderResponse message fininshed!");
		} else if (pojo instanceof AnalysisRequest) {
			log.info("Processing Analysis message started...");
			AnalysisRequest request = (AnalysisRequest) pojo;
			processor.processAnalysis(request);
			log.info("Processing Analysis message fininshed!");
		}
	}

	public String marshal(Object pojo) {
		Writer writer = new StringWriter();
		Result result = new StreamResult(writer);
		try {
			marshaller.marshal(pojo, result);
		} catch (XmlMappingException | IOException e) {
			log.error("Marshalling error!", e);
		}
		log.debug(writer.toString());
		return writer.toString();
	}

	public Object unmarshal(String xml) {
		Reader reader = new StringReader(xml);
		Source source = new StreamSource(reader);
		Object pojo = null;
		try {
			pojo = unmarshaller.unmarshal(source);
		} catch (XmlMappingException | IOException e) {
			log.error("Unmarshalling error!", e);
		}
		return pojo;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see pl.net.beercrm.ws.AbstractSSLEndpoint#getKeyStoreFile()
	 */
	@Override
	public File getKeyStoreFile() {
		try {
			return resourceLoader.getResourceAsFile(keystoreUrl);
		} catch (IOException e) {
			log.error("Key store lookup failed!", e);
		}
		return null;

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see pl.net.beercrm.ws.AbstractSSLEndpoint#getKeyStorePass()
	 */
	@Override
	public String getKeyStorePass() {
		return keystorePass;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see pl.net.beercrm.ws.AbstractSSLEndpoint#getTrustStoreFile()
	 */
	@Override
	public File getTrustStoreFile() {
		try {
			return resourceLoader.getResourceAsFile(truststoreUrl);
		} catch (IOException e) {
			log.error("Trust store lookup failed!", e);
		}
		return null;

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see pl.net.beercrm.ws.AbstractSSLEndpoint#getTrustStorePass()
	 */
	@Override
	public String getTrustStorePass() {
		return truststorePass;
	}

}
